【Python】Beautiful Soup を使ってブログ記事のテキストを抜き出してみる
形態素解析の入門中で、ブログの内容の分析を試しています。
テキストデータ取得のためにWebスクレイピングツールとして Beautiful Soup(bs4) を触っています。 Beautiful Soup は HTMLや XMLドキュメントを解析するための Pythonパッケージです。
これ単体でボリュームがあったので内容をブログ化しようと思います。
目次
環境
- OS: macOS Catalina 10.15.3
- Python: 3.7.3
- beautifulsoup4: 4.8.2
セットアップ
適当なディレクトリ上で仮想環境を作成して activate
します。
python -m venv venv source ./venv/bin/activate
必要なパッケージをインストールします。
以下 requirements.txt
を作成して pip install -r requirements.txt
を実行。
requests beautifulsoup4
以降、 Visual Studio Code 上の Jupyter Notebookでコードを書いていきました。
やってみる#1: requestsでリクエスト取得
以降で必要になるライブラリをインポートします。
from bs4 import BeautifulSoup import requests
今回は以下のブログから情報を取得してみます。
url = "https://dev.classmethod.jp/cloud/aws/aws-nw-architectures-net320/" response = requests.get(url)
ちゃんと取得できてそうですね。
やってみる#2: bs4で解析・テキスト取得
解析
response
を解析します。
soup = BeautifulSoup(response.text, 'html.parser') type(soup) # <class 'bs4.BeautifulSoup'>
解析結果は BeautifulSoupオブジェクト として格納されます。
フィルター無しでテキスト取得
get_text() でテキスト取得ができます。
単純に soup.get_text()
を行うとスクリプトやスタイルの内容も混じります。
フィルター有りでテキスト取得
HTML要素とそのクラスでフィルターを行った上で get_text()
を行います。
ページのソースを見てみると、ブログ本文は div要素の single_article_contentsクラス
であることが分かりました。
find() を使ってフィルターを行った上で get_text()
を行います。
contents = soup.find('div', class_="single_article_contents") print(contents.get_text())
良い感じに本文を取得できました。
やってみる#3: (追加) bs4で解析・テキスト取得
上の contents.get_text()
でテキスト取得はできましたが、
後の分析に向けて少し整形したい気持ちです。
色々と考慮するとキリがありませんが、 今回は以下の対応試してみます。
パラグラフのみ抽出
ブログのテキストの 多く はパラグラフ( <p>...</p>
)要素内に記述されます。
これらを抽出してみましょう。
find_all() を使用して取得します。
texts_p = [c.get_text() for c in contents.find_all('p')]
空白行、改行コードを削除する場合は、以下になります。
import re # p 要素の抽出 texts_p = [c.get_text() for c in contents.find_all('p')] # 空白行削除 + 改行コード削除 texts_p = [t.replace('\n','') for t in texts_p if re.match('\S', t)]
リストの各アイテムのみ抽出
ブログのテキストの ほとんど はパラグラフと リストアイテム ( <li>...</li>
) 要素内に記述されます。
次はリストアイテムを抽出してみます。
※処理を実装する前に Tag と NavigableString の2つの型について補足します。
find()
や find_all()
で得られた各オブジェクトは Tag と呼ばれる型です。
Tag
は複数の TagもしくはNavigableString を子供に持つ 木構造 のオブジェクトです。
以下実行します。
from bs4.element import Tag, NavigableString def parse_li(li): """ リストアイテム(li)のテキストを返す ※ li内の入れ子リストは除外する (重複するため) """ buffer = [] for child in li: if type(child) == NavigableString: buffer.append(child.string) elif type(child) == Tag: # リスト構造ではない child のみ返り値に含める if child.find_all('li') == []: buffer.append(child.get_text()) return ''.join(buffer) # li 要素の抽出 texts_li = [parse_li(li) for li in contents.find_all('li')] # 空白行削除 + 改行コード削除 texts_li = [t.replace('\n','') for t in texts_li if re.match('\S', t)]
各アイテムを一覧化できました。
おわりに
Beautiful Soup を触ってみました。 解析結果のオブジェクトの仕様さえ分かると、とても扱いやすいパッケージだなと感じます。
以下に今回の Notebookを上げています。
ブログの内容をテキストで抜き出せたので、メインの形態素解析に入門していきたい。
この記事が少しでもどなたかのお役に立てば幸いです。
参考
- Beautiful Soup
- Developers.IO